﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;

namespace PayloadTracker.OSM
{
    //TODO: Tile flushing.

    /// <summary>
    /// Class to manage all tiles.
    /// </summary>
    class TileManager
    {
        /// <summary>
        /// Fired when a tile's image has changed (eg finished downloading)
        /// </summary>
        public event TileInvalidatedDelegate TileInvalidated;

        private Dictionary<string, TileCacheEntry> m_TileCache;

        private struct TileCacheEntry
        {
            public Tile tile;
            public DateTime lastaccessed;

            public TileCacheEntry(Tile t)
            {
                tile = t;
                lastaccessed = DateTime.Now;
            }
            public void UpdateAccessedTime()
            {
                lastaccessed = DateTime.Now;
            }
        }

        public TileManager()
        {
            m_TileCache = new Dictionary<string, TileCacheEntry>();

        }
        /// <summary>
        /// Get Tiles for a specific screen region
        /// </summary>
        /// <param name="ScreenUL">Coordinate of the upper left corner of the region to retrieve tiles for</param>
        /// <param name="ScreenLR">Coordinate of the lower right corner of the region to retrieve tiles for</param>
        /// <param name="Zoom">Zoom level of the screen</param>
        /// <returns>Tiles for the region given.</returns>
        public List<Tile> GetTiles(Coordinate ScreenUL, Coordinate ScreenLR, int Zoom)
        {
            List<Tile> ret = new List<Tile>();

            var ulp = Tile.Coordinate2Tile(ScreenUL, Zoom);
            var lrp = Tile.Coordinate2Tile(ScreenLR, Zoom);

            lock (m_TileCache)
            {

                for (int x = Math.Max(0, ulp.X - 1); x <= lrp.X; x++)
                {
                    Tile tile = null;
                    for (int y = Math.Max(0, ulp.Y - 1); y <= lrp.Y; y++)
                    {
                        string tilekey = Zoom.ToString() + x.ToString() + y.ToString();

                        if (m_TileCache.ContainsKey(tilekey))
                        {
                            m_TileCache[tilekey].UpdateAccessedTime();
                            tile = m_TileCache[tilekey].tile;
                        }
                        else
                        {
                            tile = new Tile(x, y, Zoom);
                            tile.TileInvalidated += new TileInvalidatedDelegate(tile_TileInvalidated);
                            m_TileCache.Add(tilekey, new TileCacheEntry(tile));
                        }

                        ret.Add(tile);

                    }
                }


            }
            return ret;
        }

        void tile_TileInvalidated(Tile t)
        {
            TileInvalidatedDelegate del = this.TileInvalidated;
            if (del != null)
                del(t);
        }


    }
}
